/* 
 * Enterprise Library Extensions - DI + ORM.
 * Copyright (C) 2006
 *
 * GNU General Public License
 *
 * This program is free software; you can redistribute 
 * it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 */
using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

namespace ELE.EnterpriseLibrary.Data.Configuration
{
  /// <summary>
  /// Configuration data that defines a binding between an object's property and a column in a relational table.
  /// <para>For example:</para>
  /// <code>
  /// <mappings>
  ///    <add name="Mapping1" queryBuilder="Generic">
  ///      <objects>
  ///        <add name="Employee" primaryTable="employee">
  ///          <tables>
  ///            <add name="employee">
  ///              <bindings>
  ///                <add name="Id" property="Id" sqlType="INT" inName="@Id" outName="id" column="id" primaryKey="true"/>
  ///                <add name="Name" property="Name" sqlType="VARCHAR" inName="@Name" outName="name" column="name" />
  ///                <add name="Address" property="Address" refType="Address" outName="addressId" inName="@AddressId" column="addressId" />
  ///                <add name="Aliases" property="Aliases" refType="Alias" collection="true" jointBinding="EmployeeId"/>
  ///                <add name="Equipment" property="Equipment" refType="Equipment" collection="true" inName="@EmployeeId" jointColumn="employeeId"/>
  ///              </bindings>
  ///            </add>
  ///          </tables>
  ///        </add>
  ///      </objects>
  ///    </add>
  /// </mappings>
  /// </code>
  /// <para>In this section of configuration, Id, Name, Address, Aliases and Equipment are all PropertyBindingData.</para>
  /// </summary>
  public class PropertyBindingData : BasePropertyBindingData
  {
    private const string propertyProperty = "property";
    private const string sqlTypeProperty = "sqlType";
    private const string refTypeProperty = "refType";
    private const string primaryKeyProperty = "primaryKey";
    private const string columnProperty = "column";
    private const string collectionProperty = "collection";
    private const string jointBindingProperty = "jointBinding";
    private const string jointColumnProperty = "jointColumn";
    private const string jointTableProperty = "jointTable";
    /// <summary>
    /// 
    /// </summary>
    public PropertyBindingData() { }
    /// <summary>
    /// Constructor that takes in a name that identifies the binding.
    /// </summary>
    /// <param name="name"></param>
    public PropertyBindingData(string name) : base(name) { }
    /// <summary>
    /// The name of the property of the object.
    /// <para>If not provided, the name of the binding is taken as the name of the property to bind.</para>
    /// </summary>
    [ConfigurationProperty(propertyProperty, IsRequired = false)]
    public string Property
    {
      get { return (string)base[propertyProperty]; }
      set { base[propertyProperty] = value; }
    }
    /// <summary>
    /// Property that defines a string representation of a SQL type to use when using queries that refer to this binding.
    /// <para>This field is required in bindings that are not references to other bindings. In other words this property is not
    /// used in bindings where <see cref="RefType"/> is not empty.</para>
    /// </summary>
    [ConfigurationProperty(sqlTypeProperty, IsRequired = false)]
    public string SqlType
    {
      get { return (string)base[sqlTypeProperty]; }
      set { base[sqlTypeProperty] = value; }
    }
    /// <summary>
    /// Defines the reference to an <see cref="ObjectMappingData"/> configuration data. If this property is
    /// not empty, it must match the name of a mapped object under the same mapping to be valid.
    /// </summary>
    [ConfigurationProperty(refTypeProperty, IsRequired = false)]
    public string RefType
    {
      get { return (string)base[refTypeProperty]; }
      set { base[refTypeProperty] = value; }
    }
    /// <summary>
    /// Defines this binding as representing the primary key column of the enclosing table if this value is true.
    /// </summary>
    [ConfigurationProperty(primaryKeyProperty, IsRequired = false, DefaultValue=false)]
    public bool PrimaryKey
    {
      get { return (bool)base[primaryKeyProperty]; }
      set { base[primaryKeyProperty] = value; }
    }
    /// <summary>
    /// The name of the column in the enclosing table that this binding represents.
    /// <para>This property is not needed if the binding is defined as a reference of collection type, 
    /// in other words <see cref="RefType"/> is not empty and <see cref="IsCollection"/> is set to true.</para>
    /// </summary>
    [ConfigurationProperty(columnProperty, IsRequired = false)]
    public string ColumnName
    {
      get { return (string)base[columnProperty]; }
      set { base[columnProperty] = value; }
    }
    /// <summary>
    /// Defines a one to many relationship between this binding and another binding in the enclosing mapping.
    /// <para>If a binding is defined as a collection (this property's value is true), <see cref="RefType"/> must 
    /// be set to a valid reference mapping object and either:
    /// <list type="bullet">
    ///   <item><see cref="JointBinding"/> is set to a valid binding within the referenced object mapping</item>
    ///   <item><see cref="JointColumn"/> is set to a existent column on the primary table of the referenced object mapping
    ///   and <see cref="BasePropertyBindingData.InName"/> is not empty.</item>
    ///   <item><see cref="JointColumn"/> is set to the name of an existent column on the table defined by <see cref="JointTable"/> in 
    ///    the referenced object mapping  and <see cref="BasePropertyBindingData.InName"/> is not empty.</item>
    /// </list>
    /// </para>
    /// </summary>
    [ConfigurationProperty(collectionProperty, IsRequired = false, DefaultValue = false)]
    public bool IsCollection
    {
      get { return (bool)base[collectionProperty]; }
      set { base[collectionProperty] = value; }
    }
    /// <summary>
    /// Represents a binding that is used to join this binding with a referenced object mapping.
    /// <para>Not needed if <see cref="RefType"/> is not set in this binding.</para>
    /// </summary>
    [ConfigurationProperty(jointBindingProperty, IsRequired = false)]
    public string JointBinding
    {
      get { return (string)base[jointBindingProperty]; }
      set { base[jointBindingProperty] = value; }
    }
    /// <summary>
    /// Represents a column on the primary table of a referenced object mapping
    /// that is used as a joint with this binding.
    /// <para>Not needed if <see cref="RefType"/> is not set in this binding.</para>
    /// <para>If this property is set, <see cref="BasePropertyBindingData.InName"/> must be defined.</para>
    /// <para>If the referenced column is not in the primary table of the referenced object mapping, 
    /// <see cref="JointTable"/> must be defined to a valid table in the referenced object mapping.</para>
    /// </summary>
    [ConfigurationProperty(jointColumnProperty, IsRequired = false)]
    public string JointColumn
    {
      get { return (string)base[jointColumnProperty]; }
      set { base[jointColumnProperty] = value; }
    }
    /// <summary>
    /// This property is used in conjuction with <see cref="JointColumn"/> is the case that the
    /// reference is not to the primary table of the referenced object mapping.
    /// <para>Not needed if <see cref="RefType"/> is not set in this binding.</para>
    /// <para>If this property is set, <see cref="JointColumn"/> must be defined and <see cref="JointBinding"/> is not used.</para>
    /// </summary>
    [ConfigurationProperty(jointTableProperty, IsRequired = false)]
    public string JointTable
    {
      get { return (string)base[jointTableProperty]; }
      set { base[jointTableProperty] = value; }
    }
  }
}
